home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / wil4c10.zip / FTP.C < prev    next >
C/C++ Source or Header  |  1997-07-26  |  31KB  |  933 lines

  1. /*
  2. **  FTP.C
  3. **
  4. **  FTP client, uses ASYNC functions.
  5. **
  6. **  NOTE: The order of the FTP_* messages in message.h should match
  7. **        the order in FTP.RC.
  8. */
  9.  
  10. #include <windows.h>
  11. #include <winsock.h>
  12.  
  13. #include "wil.h"
  14. #include "about.h"
  15. #include "async.h"
  16. #include "message.h"
  17. #include "paint.h"
  18. #include "readini.h"
  19. #include "str.h"
  20.  
  21. #ifdef WIN32
  22. #define USE_INS HINSTANCE
  23. #define USE_PTR PSTR
  24. #else
  25. #define USE_INS HANDLE
  26. #define USE_PTR LPSTR
  27. #endif
  28.  
  29. LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
  30.  
  31. /* globals */
  32.  
  33. HWND hMainWnd;            /* main window handle */
  34.  
  35. #define BS          8
  36. #define LF         10
  37. #define CR         13
  38. #define ESC        27
  39.  
  40. #define MAX_BUF   512
  41. #define MAX_STR    50
  42.  
  43. #define HALF_SEC  500
  44. #define ONE_SEC  1000
  45. #define TWO_SEC  2000
  46. #define FIVE_SEC 5000
  47. #define TEN_SEC 10000
  48.  
  49. #define FTP_PORT   21
  50.  
  51. #define FIRST_DATA_PORT   6145
  52. #define LAST_DATA_PORT    6175
  53.  
  54. #define FTP_CONN_SUCCESS   101
  55. #define FTP_CONN_FAILURE   102
  56. #define FTP_USER_SUCCESS   103
  57. #define FTP_PASS_SUCCESS   104
  58.  
  59. #define FTP_CMD_SUCCESS    201
  60. #define FTP_CMD_FAILURE    202
  61. #define FTP_QUIT_SUCCESS   203
  62.  
  63. #define FTP_LIST_BEGIN     301
  64. #define FTP_LIST_SUCCESS   302
  65. #define FTP_LIST_READY     303
  66. #define FTP_LIST_INCOMING  304
  67.  
  68. #define FTP_GET_BEGIN      401
  69. #define FTP_GET_SUCCESS    402
  70. #define FTP_GET_READY      403
  71. #define FTP_GET_INCOMING   404
  72.  
  73. #define FTP_PUT_BEGIN      501
  74. #define FTP_PUT_SUCCESS    502
  75. #define FTP_PUT_READY      503
  76. #define FTP_PUT_SENDING    504
  77.  
  78. static USE_INS hInstance;
  79. static int  WinWidth = 8 * NCOLS;     /* window width */
  80. static int  WinHeight = 15 * NROWS;   /* window height */
  81. static char Temp[MAX_BUF+8];          /* temporary buffer */
  82. static int  InBufCmd = 0;             /* command */
  83. static int  InBufLen = 0;             /* length of string in InBuffer[] */
  84. static char InBuffer[MAX_BUF+1];      /* buffer for input */
  85. static SOCKET ControlSock = 0;        /* control socket */
  86. static SOCKET ListenSock = 0;         /* listen socket */
  87. static SOCKET DataSock = 0;           /* data socket */
  88. static ULONG  MyHostAddr = 0;         /* address of local host */
  89. static char   MyDottedAddr[17];       /* dotted notation of <MyHostAddr> */
  90. static int    ConnectedFlag = 0;      /* connected to FTP server if TRUE */
  91. static short DataPort = FIRST_DATA_PORT; /* data port number */
  92. static int   FileHandle = 0;          /* file handle */
  93. static char  Filename[256] = "\0";    /* filename buffer */
  94. static long  RxBytes;                 /* # bytes received */
  95. static long  TxBytes;                 /* # bytes transmitted */
  96. static HCURSOR ArrowCursor;           /* arrow cursor */
  97. static HCURSOR WaitCursor;            /* hour glass cursor */
  98. static char  UserString[MAX_STR] = "";/* user login name */
  99. static char  PassString[MAX_STR] = "";/* user login password */
  100. static DWORD ListenerTimeMark = 0;    /* system timer time mark */
  101. static int   Want2Tx;                 /* bytes want to send */
  102.  
  103. /* put cursor in window */
  104.  
  105. static void SetTheFocus(void)
  106. {/* create client area caret */
  107.  CreateCaret(hMainWnd,NULL,3,10);
  108.  SetCaretPos(PaintGetColPos(),PaintGetRowPos());
  109.  ShowCaret(hMainWnd);
  110. }
  111.  
  112. /* disable range of menu items */
  113.  
  114. static void DisableMenuItems(int First, int Last)
  115. {int i;
  116.  HMENU hMenu;
  117.  hMenu = GetMenu(hMainWnd);
  118.  for(i=First;i<=Last;i++)
  119.     EnableMenuItem(hMenu,i,MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
  120.  DrawMenuBar(hMainWnd);
  121. }
  122.  
  123. /* enable range of menu items */
  124.  
  125. static void EnableMenuItems(int First, int Last)
  126. {int i;
  127.  HMENU hMenu;
  128.  hMenu = GetMenu(hMainWnd);
  129.  for(i=First;i<=Last;i++)
  130.     EnableMenuItem(hMenu,i,MF_BYCOMMAND | MF_ENABLED);
  131.  DrawMenuBar(hMainWnd);
  132. }
  133.  
  134. /* menu state when not connected, awaiting user input */
  135.  
  136. void NotConnectedMenuState(void)
  137. {EnableMenuItems(MSG_FTP_CONNECT, MSG_FTP_CONNECT);
  138.  DisableMenuItems(MSG_FTP_CWD, MSG_FTP_QUIT);
  139. }
  140.  
  141. /* menu state when connected, awaiting user input */
  142.  
  143. void ConnectedMenuState(void)
  144. {DisableMenuItems(MSG_FTP_CONNECT, MSG_FTP_CONNECT);
  145.  EnableMenuItems(MSG_FTP_CWD, MSG_FTP_QUIT);
  146. }
  147.  
  148. /* menu state while executing FTP command */
  149.  
  150. void DoingCmdMenuState(void)
  151. {DisableMenuItems(MSG_FTP_CONNECT, MSG_FTP_QUIT);
  152. }
  153.  
  154. /* display error text */
  155.  
  156. static void DisplayError(int Code, LPSTR Msg)
  157. {wsprintf((LPSTR)Temp, "ERROR %d:", Code);
  158.  DisplayString((LPSTR)Temp);
  159.  if(Msg) DisplayString(Msg);
  160.  if(Code)
  161.    {wilErrorText(Code,(LPSTR)Temp,50);
  162.     DisplayLine((LPSTR)Temp);
  163.    }
  164.  SetCursor(ArrowCursor);
  165. }
  166.  
  167. /* add character to input buffer */
  168.  
  169. static void Add2Buffer(char Chr)
  170. {int i;
  171.  /* add char to input buffer */
  172.  switch(Chr)
  173.    {case BS:
  174.       if(InBufLen>0)
  175.         {/* backup on screen */
  176.          DisplayChar(BS);
  177.          /* remove last char from buffer */
  178.          InBufLen--;
  179.         }
  180.       break;
  181.     case ESC:
  182.       for(i=1;i<=InBufLen;i++) DisplayChar(BS);
  183.       InBufLen = 0;
  184.       DestroyCaret();
  185.       break;
  186.     default:
  187.       /* display char */
  188.       DisplayChar(Chr);
  189.       /* put into buffer */
  190.       if(InBufLen<MAX_BUF) InBuffer[InBufLen++] = Chr;
  191.       break;
  192.    }
  193. }
  194.  
  195. /* display socket status */
  196.  
  197. static void CheckSocket(LPSTR Msg, SOCKET Socket)
  198. {int Read  = wilSocketStatus(Socket,WIL_READ_STATUS);
  199.  int Write = wilSocketStatus(Socket,WIL_WRITE_STATUS);
  200.  int Error = wilSocketStatus(Socket,WIL_ERROR_STATUS);
  201.  wsprintf((LPSTR)Temp,"%s %d R:%d W:%d E:%d",Msg,Socket,Read,Write,Error);
  202.  DisplayLine((LPSTR)Temp);
  203. }
  204.  
  205. /* still connected ? */
  206.  
  207. static int StillConnected(void)
  208. {if(wilIsConnected(ControlSock,0)) return TRUE;
  209.  DisplayLine("Connection to FTP host lost");
  210.  return FALSE;
  211. }
  212.  
  213. /* accept data connection */
  214.  
  215. static int FtpAccept(void)
  216. {
  217.  DataSock = wilAccept(ListenSock,(long)ONE_SEC);
  218.  if((int)DataSock<0)
  219.    {DisplayError((int)DataSock, "Accept:");
  220.     return FALSE;
  221.    }
  222.  DisplayLine("Connection is accepted");
  223.  return TRUE;
  224. }
  225.  
  226. /* set up listener socket */
  227.  
  228. static int FtpListen(void)
  229. {int Code;
  230.  /* set up listener socket */
  231.  ListenSock = wilTcpSocket();
  232.  if((int)ListenSock<=0)
  233.     {DisplayError((int)ListenSock, "wilListen:");
  234.      return FALSE;
  235.     }
  236.  /* bind port address to socket */
  237.  wsprintf((LPSTR)Temp,"Binding %s to port %d",(LPSTR)MyDottedAddr, DataPort);
  238.  DisplayLine((LPSTR)Temp);
  239.  Code = wilBind(ListenSock, MyHostAddr, DataPort);
  240.  if(Code<0)
  241.     {DisplayError((int)Code, "wilBind:");
  242.      return FALSE;
  243.     }
  244.  /* listen for connection attempt */
  245.  Code = wilListen(ListenSock,1);
  246.  if(Code<0)
  247.    {DisplayError(Code, "wilListen:");
  248.     return FALSE;
  249.    }
  250.  return TRUE;
  251. }
  252.  
  253. /* get any outstanding incoming data from control socket */
  254.  
  255. static void GetControlIncoming(void)
  256. {int Code;
  257.  /* any more control socket response ? */
  258.  while(wilDataIsReady(ControlSock,0))
  259.    {Code = wilReadString(ControlSock,(LPSTR)InBuffer,MAX_BUF);
  260.     if(Code<=0) break;
  261.     DisplayString((LPSTR)InBuffer);
  262.    }
  263. }
  264.  
  265. /* find local socket address */
  266.  
  267. ULONG GetAddrFromSock(SOCKET Socket, LPSTR DottedAddr)
  268. {ULONG HostAddr;
  269.  /* get address from socket */
  270.  HostAddr = wilLocalSockAddr(Socket);
  271.  wsprintf((LPSTR)DottedAddr,"%1ld.%1ld.%1ld.%1ld",
  272.                      0x000000ff & (HostAddr>>24),
  273.                      0x000000ff & (HostAddr>>16),
  274.                      0x000000ff & (HostAddr>>8),
  275.                      0x000000ff & (HostAddr) );
  276.  wsprintf((LPSTR)Temp,"LocalSockAddr = %s (%lx) ",
  277.                     (LPSTR)DottedAddr, HostAddr);
  278.  DisplayLine((LPSTR)Temp);
  279.  return HostAddr;
  280. }
  281.  
  282. /* WinMain */
  283.  
  284. #ifdef WIN32
  285. int WINAPI
  286. #else
  287. int PASCAL
  288. #endif
  289. WinMain(USE_INS hInst, USE_INS hPrevInstance,
  290.         USE_PTR szCmdLine,  int nCmdShow)
  291. {WNDCLASS  wc;
  292.  MSG msg;
  293.  BOOL Result;
  294.  if(!hPrevInstance)
  295.    {/* register main window class */
  296.     wc.style = CS_HREDRAW | CS_VREDRAW;
  297.     wc.lpfnWndProc = MainWndProc;
  298.     wc.cbClsExtra = 0;
  299.     wc.cbWndExtra = 0;
  300.     wc.hInstance = hInst;
  301.     wc.hIcon = LoadIcon(hInst, "HostIcon");
  302.     wc.hCursor = NULL;
  303.     wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  304.     wc.lpszMenuName =  "HostMenu";
  305.     wc.lpszClassName = "HostWClass";
  306.     Result = RegisterClass(&wc);
  307.     if(!Result) return FALSE;
  308.    }
  309.  
  310.  /* create main window */
  311.  hInstance = hInst;
  312.  hMainWnd = CreateWindow(
  313.         "HostWClass",   "FTP",    WS_OVERLAPPEDWINDOW,
  314.         CW_USEDEFAULT,  CW_USEDEFAULT,
  315.         WinWidth,       WinHeight,
  316.         NULL,           NULL,
  317.         hInstance,      NULL);
  318.  ShowWindow(hMainWnd, nCmdShow);
  319.  UpdateWindow(hMainWnd);
  320.  
  321.  /* window control loop */
  322.  
  323.  while(GetMessage(&msg,NULL,0,0))
  324.    {
  325.     TranslateMessage(&msg);
  326.     DispatchMessage(&msg);
  327.    }
  328.  return (msg.wParam);
  329. } /* end WinMain */
  330.  
  331. #ifdef WIN32
  332. LRESULT CALLBACK
  333. #else
  334. long FAR PASCAL
  335. #endif
  336. MainWndProc(HWND hWindow,UINT iMsg,WPARAM wParam,LPARAM lParam)
  337. {int Code;
  338.  HDC hDC;
  339.  PAINTSTRUCT ps;
  340.  int i;
  341.  LPSTR  Ptr;
  342. #ifdef WIN32
  343. #else
  344.  static FARPROC lpfnAboutDlgProc;
  345. #endif
  346.  /* begin */
  347.  hMainWnd = hWindow;
  348.  switch (iMsg)
  349.     {case WM_CREATE:
  350.       /* create cursors */
  351.       ArrowCursor = LoadCursor(NULL, IDC_ARROW);
  352.       WaitCursor = LoadCursor(NULL, IDC_WAIT);
  353.       SetCursor(ArrowCursor);
  354. #ifdef WIN32
  355. #else
  356.        /* create thunk for Win16 */
  357.        lpfnAboutDlgProc = MakeProcInstance(AboutDlgProc,hInstance);
  358. #endif
  359.       /* initialize paint module */
  360.       PaintInit();
  361.       /* attach WINSOCK */
  362.       DisplayString("Attaching WINSOCK...");
  363.       Code = wilAttach();
  364.       DisplayLine("OK");
  365.       if(Code<0) DisplayError(Code,"wilAttach fails:");
  366.       else
  367.         {wsprintf((LPSTR)Temp," Description: %s", wilGetDescription() );
  368.          DisplayLine((LPSTR)Temp);
  369.          wsprintf((LPSTR)Temp," My HostName: %s", wilGetMyHostName() );
  370.          DisplayLine((LPSTR)Temp);
  371.          Ptr = (LPSTR) wilGetMyHostDotted(0);
  372.          wsprintf((LPSTR)Temp," My HostAddr: %s", Ptr );
  373.          DisplayLine((LPSTR)Temp);
  374.          lstrcpy((LPSTR)MyDottedAddr, (LPSTR)Ptr);
  375.          MyHostAddr = wilGetMyHostAddr(0);
  376.         }
  377.        NotConnectedMenuState();
  378.        *InBuffer = '\0';
  379.        *Temp = '\0';
  380.        /* open FTP.INI file */
  381.        if(!IniOpen("FTP.INI")) break;
  382.        DisplayLine("FTP.INI opened");
  383.        while(1)
  384.          {/* read next line from FTP.INI */
  385.           if(IniRead((LPSTR)Temp)<0) break;
  386.           DisplayLine((LPSTR)Temp);
  387.           /* test for all legal keywords */
  388.           IniExtract((LPSTR)Temp,"USER",(LPSTR)UserString);
  389.           IniExtract((LPSTR)Temp,"PASS",(LPSTR)PassString);
  390.          }
  391. #if 0
  392.        /* echo login name & password */
  393.        wsprintf((LPSTR)Temp,"UserString=[%s]",(LPSTR)UserString);
  394.        DisplayLine((LPSTR)Temp);
  395.        wsprintf((LPSTR)Temp,"PassString=[%s]",(LPSTR)PassString);
  396.        DisplayLine((LPSTR)Temp);
  397. #endif
  398.        /* verify that we have login name & password */
  399.        if(lstrlen((LPSTR)UserString)==0) DisplayLine("ERROR: Missing FTP login user name.");
  400.        if(lstrlen((LPSTR)PassString)==0) DisplayLine("ERROR: Missing FTP login password.");
  401.        break;
  402.  
  403.      case WM_COMMAND:
  404.          switch(wParam)
  405.            {case MSG_ABOUT:
  406. #ifdef WIN32
  407.                DialogBox(hInstance, "AboutBox", hMainWnd, AboutDlgProc);
  408. #else
  409.                DialogBox(hInstance, "AboutBox", hMainWnd, lpfnAboutDlgProc);
  410. #endif
  411.                return 0;
  412.  
  413.             case MSG_BREAK:
  414.               wilCancelBlocking();
  415.               if(ConnectedFlag) ConnectedMenuState();
  416.               else NotConnectedMenuState();
  417.               /* anything in control sock ? */
  418.               GetControlIncoming();
  419.               DataPort++;
  420.               break;
  421.  
  422.             case MSG_EXIT:
  423.               /* close all sockets & exit */
  424.               if(ControlSock) wilCloseSocket(ControlSock);
  425.               if(ListenSock) wilCloseSocket(ListenSock);
  426.               if(DataSock) wilCloseSocket(DataSock);
  427.               wilRelease();
  428.               DestroyWindow(hMainWnd);
  429.               break;
  430.  
  431.             case MSG_DEBUG:
  432.               CheckSocket("ControlSock", ControlSock);
  433.               if(ListenSock) CheckSocket("ListenSock", ListenSock);
  434.               if(DataSock)  CheckSocket("DataSock", DataSock);
  435.               *InBuffer = '\0';
  436.               break;
  437.  
  438.             case MSG_FTP_CONNECT:
  439.               /* connect to remote host */
  440.               InBufLen = 0;
  441.               InBufCmd = MSG_FTP_CONNECT;
  442.               DisplayString("Enter FTP address:");
  443.               SetTheFocus();
  444.               DoingCmdMenuState();
  445.               break;
  446.  
  447.             case MSG_FTP_QUIT:
  448.               /* quit FTP session */
  449.               if(!StillConnected()) break;
  450.               DoingCmdMenuState();
  451.               AsyncCommand("QUIT", FTP_QUIT_SUCCESS, FTP_CMD_FAILURE,
  452.                                    ASYNC_MULTIPLE_CODED);
  453.               ConnectedFlag = 0;
  454.               break;
  455.  
  456.             case MSG_FTP_CWD:
  457.               /* change working directory */
  458.               InBufLen = 0;
  459.               InBufCmd = MSG_FTP_CWD;
  460.               DisplayString("Enter directory:");
  461.               SetTheFocus();
  462.               DoingCmdMenuState();
  463.               break;
  464.  
  465.             case MSG_FTP_BINARY:
  466.               /* set binary transfer mode */
  467.               if(!StillConnected()) break;
  468.               DoingCmdMenuState();
  469.               AsyncCommand("TYPE I", FTP_CMD_SUCCESS, FTP_CMD_FAILURE,
  470.                            ASYNC_MULTIPLE_CODED);
  471.               break;
  472.  
  473.             case MSG_FTP_ASCII:
  474.               /* set ascii transfer mode */
  475.               if(!StillConnected()) break;
  476.               DoingCmdMenuState();
  477.               AsyncCommand("TYPE A", FTP_CMD_SUCCESS, FTP_CMD_FAILURE,
  478.                            ASYNC_MULTIPLE_CODED);
  479.               break;
  480.  
  481.             case MSG_FTP_LIST:
  482.               /* list files */
  483.               if(!StillConnected()) break;
  484.               DoingCmdMenuState();
  485.               /* transmit PORT command */
  486.               wsprintf((LPSTR)Temp,"PORT %s,%1d,%1d", (LPSTR)MyDottedAddr,
  487.                       (DataPort>>8), (0x00ff&DataPort) );
  488.               /* replace dots with commas in PORT command */
  489.               for(i=5;i<=16;i++) if(Temp[i]=='.') Temp[i] = ',';
  490.               AsyncCommand((LPSTR)Temp, FTP_LIST_SUCCESS, FTP_CMD_FAILURE,
  491.                            ASYNC_MULTIPLE_CODED);
  492.               break;
  493.  
  494.             case MSG_FTP_GET:
  495.               /* get (receive) file */
  496.               if(!StillConnected()) break;
  497.               DoingCmdMenuState();
  498.               InBufLen = 0;
  499.               InBufCmd = MSG_FTP_GET;
  500.               DisplayString("Enter filename to receive:");
  501.               SetTheFocus();
  502.               DoingCmdMenuState();
  503.               break;
  504.  
  505.             case MSG_FTP_PUT:
  506.               /* put (send) file */
  507.               if(!StillConnected()) break;
  508.               InBufLen = 0;
  509.               InBufCmd = MSG_FTP_PUT;
  510.               DisplayString("Enter filename to send:");
  511.               SetTheFocus();
  512.               DoingCmdMenuState();
  513.               break;
  514.            }
  515.          break;
  516.  
  517.     case WM_PAINT:
  518.       HideCaret(hMainWnd);
  519.       hDC = BeginPaint(hMainWnd, &ps);
  520.       SetMapMode(hDC,MM_ANISOTROPIC);
  521.       SelectObject(hDC, GetStockObject(OEM_FIXED_FONT) );
  522.       PaintMain(hDC,&ps);
  523.       EndPaint(hMainWnd,&ps);
  524.       SetCaretPos(PaintGetColPos(),PaintGetRowPos());
  525.       ShowCaret(hMainWnd);
  526.       break;
  527.  
  528.     case WM_DESTROY:
  529.       PostQuitMessage(0);
  530.       break;
  531.  
  532.     case WM_USER: /* posted by WIL */
  533.       AsyncProcessMsg(lParam);
  534.       break;
  535.  
  536.     case WM_USER+1:  /* posted by Async functions */
  537.       /* get response code */
  538.       if(lParam>=500)
  539.         {/* FTP server returns fatal error code */
  540.          POST_MSG(FTP_CMD_FAILURE);
  541.          break;
  542.         }
  543.       /* execute case */
  544.       switch(wParam)
  545.         {
  546.          case FTP_CONN_SUCCESS:
  547.            /* we are now connected. log on to server */
  548.            DisplayLine("Connected to FTP server. Logging on...");
  549.            wsprintf((LPSTR)Temp,"USER %s",(LPSTR)UserString);
  550.            AsyncCommand((LPSTR)Temp, FTP_USER_SUCCESS, FTP_CONN_FAILURE,
  551.                                      ASYNC_MULTIPLE_CODED);
  552.            break;
  553.  
  554.          case FTP_USER_SUCCESS:
  555.            /* USER command was successful */
  556.            wsprintf((LPSTR)Temp,"PASS %s",(LPSTR)PassString);
  557.            AsyncCommand((LPSTR)Temp, FTP_PASS_SUCCESS, FTP_CONN_FAILURE,
  558.                                      ASYNC_MULTIPLE_CODED);
  559.            break;
  560.  
  561.          case FTP_PASS_SUCCESS:
  562.            /* PASS command was successful */
  563.            ConnectedFlag = TRUE;
  564.            DisplayLine("Logged on to FTP server.");
  565.            ConnectedMenuState();
  566.            SetCursor(ArrowCursor);
  567.            break;
  568.  
  569.          case FTP_CONN_FAILURE:
  570.            /* FTP connection has failed */
  571.            DisplayLine("Cannot CONNECT");
  572.            NotConnectedMenuState();
  573.            SetCursor(ArrowCursor);
  574.            break;
  575.  
  576.          /*** QUIT command ***/
  577.  
  578.          case FTP_QUIT_SUCCESS:
  579.            /* QUIT command was successful */
  580.            ConnectedFlag = TRUE;
  581.            NotConnectedMenuState();
  582.            SetCursor(ArrowCursor);
  583.            break;
  584.  
  585.          case FTP_CMD_SUCCESS:
  586.            /* FTP command was successful */
  587.            ConnectedMenuState();
  588.            DisplayLine("FTP command succeeds.");
  589.            SetCursor(ArrowCursor);
  590.            break;
  591.  
  592.          case FTP_CMD_FAILURE:
  593.            /* FTP command has failed */
  594.            DisplayLine("FTP command fails...");
  595.            ConnectedMenuState();
  596.            SetCursor(ArrowCursor);
  597.            break;
  598.  
  599.          /*** LIST command (from case ) ***/
  600.  
  601.          case FTP_LIST_SUCCESS:
  602.            /* PORT command was successful */
  603.            if(!FtpListen()) break;
  604.            /* ask server to send list of files */
  605.            ListenerTimeMark = GetCurrentTime() + TEN_SEC;
  606.            AsyncCommand("LIST", FTP_LIST_READY, FTP_CMD_FAILURE,
  607.                            ASYNC_MULTIPLE_CODED);
  608.            break;
  609.  
  610.          case FTP_LIST_READY:
  611.            /* LIST command was successful */
  612.            if(GetCurrentTime() > ListenerTimeMark)
  613.              {/* where's the data ? */
  614.               DisplayLine("Listener socket is silent . . .");
  615.               wilCloseSocket(ListenSock);
  616.               POST_MSG(FTP_CMD_FAILURE);
  617.               break;
  618.              }
  619.            /* any incoming on listener socket ? */
  620.            if(wilDataIsReady(ListenSock,500))
  621.              {/* accept connection [get DataSock] */
  622.               FtpAccept();
  623.               POST_MSG(FTP_LIST_INCOMING);
  624.              }
  625.            else
  626.              {/* nothing on data socket yet */
  627.               POST_MSG(FTP_LIST_READY);
  628.              }
  629.            break;
  630.  
  631.          case FTP_LIST_INCOMING:
  632.            DisplayLine("Reading data from data socket...");
  633.            /* data socket has data */
  634.            while(1)
  635.              {/* read next line from server */
  636.               if(!wilDataIsReady(DataSock,750)) break;
  637.               Code = wilReadLine(DataSock,(LPSTR)InBuffer,MAX_BUF);
  638.               if(Code<=0) break;
  639.               /* display data just read */
  640.               DisplayString((LPSTR)InBuffer);
  641.              }
  642.            *InBuffer = '\0';
  643.            DisplayLine("[END]");
  644.            /* close listener & data socket */
  645.            wilCloseSocket(DataSock);
  646.            wilCloseSocket(ListenSock);
  647.            if(++DataPort>LAST_DATA_PORT) DataPort = FIRST_DATA_PORT;
  648.            /* any more control socket response ? */
  649.            GetControlIncoming();
  650.            POST_MSG(FTP_CMD_SUCCESS);
  651.            break;
  652.  
  653.          /*** GET command ***/
  654.  
  655.          case FTP_GET_BEGIN:
  656.            /* issue PORT command */
  657.            wsprintf((LPSTR)Temp,"PORT %s,%1d,%1d", (LPSTR)MyDottedAddr,
  658.                    (DataPort>>8), (0x00ff&DataPort) );
  659.            /* replace dots with commas in PORT command */
  660.            for(i=5;i<=16;i++) if(Temp[i]=='.') Temp[i] = ',';
  661.            AsyncCommand((LPSTR)Temp, FTP_GET_SUCCESS, FTP_CMD_FAILURE,
  662.                         ASYNC_MULTIPLE_CODED);
  663.            break;
  664.  
  665.          case FTP_GET_SUCCESS:
  666.            /* PORT command was successful, ask server to send file */
  667.            if(!FtpListen()) break;
  668.            wsprintf((LPSTR)Temp,"RETR %s",(LPSTR)Filename);
  669.            ListenerTimeMark = GetCurrentTime() + TEN_SEC;
  670.            AsyncCommand((LPSTR)Temp, FTP_GET_READY, FTP_CMD_FAILURE,
  671.                            ASYNC_MULTIPLE_CODED);
  672.            break;
  673.  
  674.          case FTP_GET_READY:
  675.            /* RETR command was successful */
  676.            if(GetCurrentTime() > ListenerTimeMark)
  677.              {/* where's the data ? */
  678.               DisplayLine("Listener socket is silent . . .");
  679.               wilCloseSocket(ListenSock);
  680.               POST_MSG(FTP_CMD_FAILURE);
  681.               break;
  682.              }
  683.            /* any incoming on listener socket ? */
  684.            if(wilDataIsReady(ListenSock,0))
  685.              {/* accept connection [get DataSock] */
  686.               FtpAccept();
  687.               /* any control socket response ? */
  688.               GetControlIncoming();
  689.               DisplayLine("Reading data from data socket...");
  690.               /* receive data on DataSock */
  691.               RxBytes = 0;
  692.               POST_MSG(FTP_GET_INCOMING);
  693.              }
  694.            else POST_MSG(FTP_GET_READY);
  695.            break;
  696.  
  697.          case FTP_GET_INCOMING:
  698.            /* get incoming data */
  699.            while(1)
  700.              {/* get next buffer */
  701.               Code = wilReadSocket(DataSock,(LPSTR)InBuffer, MAX_BUF);
  702.               if(Code==0)
  703.                  {/* socket open, but no data is ready */
  704.                   POST_MSG(FTP_GET_INCOMING);
  705.                   break;
  706.                  }
  707.               if(Code==WIL_EOF)
  708.                  {/* no more data */
  709.                   wsprintf((LPSTR)Temp,"[EOF] %ld bytes received", RxBytes);
  710.                   DisplayLine((LPSTR)Temp);
  711.                   _lclose(FileHandle);
  712.                   /* close listener & data socket */
  713.                   wilCloseSocket(DataSock);
  714.                   wilCloseSocket(ListenSock);
  715.                   if(++DataPort>LAST_DATA_PORT) DataPort = FIRST_DATA_PORT;
  716.                   /* any more control socket response ? */
  717.                   GetControlIncoming();
  718.                   /* we're done */
  719.                   MessageBeep(MB_ICONEXCLAMATION);
  720.                   POST_MSG(FTP_CMD_SUCCESS);
  721.                   break;
  722.                  }
  723.               if(Code<0)
  724.                 {DisplayError(Code, "DataRead");
  725.                  break;
  726.                 }
  727.               /* Code > 0, so count received bytes */
  728.               RxBytes += (long)Code;
  729.               wsprintf((LPSTR)Temp,"%ld\r",RxBytes);
  730.               DisplayString((LPSTR)Temp);
  731.               /* save buffer to disk */
  732.               Code = _lwrite(FileHandle,(LPSTR)InBuffer,Code);
  733.               if(Code<0)
  734.                 {wsprintf((LPSTR)Temp,"Error %d returned writing to %s",
  735.                          Code, Filename);
  736.                  DisplayLine((LPSTR)Temp);
  737.                  _lclose(FileHandle);
  738.                  break;
  739.                 }
  740.              }
  741.            break;
  742.  
  743.            /*** PUT command ***/
  744.  
  745.          case FTP_PUT_BEGIN:
  746.            /* issue PORT command */
  747.            wsprintf((LPSTR)Temp,"PORT %s,%1d,%1d", (LPSTR)MyDottedAddr,
  748.                     (DataPort>>8), (0x00ff&DataPort) );
  749.            /* replace dots with commas in PORT command */
  750.            for(i=5;i<=16;i++) if(Temp[i]=='.') Temp[i] = ',';
  751.            AsyncCommand((LPSTR)Temp, FTP_PUT_SUCCESS, FTP_CMD_FAILURE,
  752.                         ASYNC_MULTIPLE_CODED);
  753.            break;
  754.  
  755.          case FTP_PUT_SUCCESS:
  756.            /* PORT command was successful, ask server to receive file */
  757.            if(!FtpListen()) break;
  758.            wsprintf((LPSTR)Temp,"STOR %s",(LPSTR)Filename);
  759.            ListenerTimeMark = GetCurrentTime() + TWO_SEC;
  760.            AsyncCommand((LPSTR)Temp, FTP_PUT_READY, FTP_CMD_FAILURE,
  761.                            ASYNC_MULTIPLE_CODED);
  762.            break;
  763.  
  764.          case FTP_PUT_READY:
  765.            /* STOR command was successful */
  766.            if(GetCurrentTime() > ListenerTimeMark)
  767.              {/* where's the data ? */
  768.               DisplayLine("Listener socket is silent . . .");
  769.               wilCloseSocket(ListenSock);
  770.               POST_MSG(FTP_CMD_FAILURE);
  771.               break;
  772.              }
  773.            /* any incoming on listener socket ? */
  774.            if(wilDataIsReady(ListenSock,0))
  775.              {/* accept connection [get DataSock] */
  776.               if(FtpAccept()) POST_MSG(FTP_PUT_SENDING);
  777.              }
  778.            else POST_MSG(FTP_PUT_READY);
  779.            break;
  780.  
  781.          case FTP_PUT_SENDING:
  782.            /* send data */
  783.            TxBytes = 0;
  784.            while(1)
  785.              {/* read from disk */
  786.               Code = _lread(FileHandle,(LPSTR)InBuffer,MAX_BUF);
  787.               if(Code<0)
  788.                 {wsprintf((LPSTR)Temp,"Error %d returned reading from %s",
  789.                          Code, Filename);
  790.                  DisplayLine((LPSTR)Temp);
  791.                  _lclose(FileHandle);
  792.                  break;
  793.                 }
  794.               if(Code==0) break;
  795.               /* Code>0: write to socket */
  796.               Want2Tx = Code;
  797.               Ptr = (LPSTR) InBuffer;
  798.               /* write all of data to socket */
  799.               while(Want2Tx > 0)
  800.                 {if(!StillConnected()) break;
  801.                  Code = wilWriteSocket(DataSock, Ptr, Want2Tx);
  802.                  if(Code==0) break;
  803.                  if(Code==WIL_EOF) break;
  804.                  if(Code<0)
  805.                    {DisplayError(Code, "DataWrite");
  806.                     break;
  807.                    }
  808.                  /* Code > 0 */
  809.                  Want2Tx -= Code;
  810.                  TxBytes += (long)Code;
  811.                  /* advance pointer */
  812.                  Ptr += Code;
  813.                 }
  814.               /* display transmitted bytes */
  815.               wsprintf((LPSTR)Temp,"%ld\r",TxBytes);
  816.               DisplayString((LPSTR)Temp);
  817.              }
  818.            /* no more data to send */
  819.            wsprintf((LPSTR)Temp,"[END] %ld bytes sent", TxBytes);
  820.            DisplayLine((LPSTR)Temp);
  821.            _lclose(FileHandle);
  822.            /* close the data socket */
  823.            MessageBeep(MB_ICONEXCLAMATION);
  824.            /* close listener & data socket */
  825.            wilCloseSocket(DataSock);
  826.            wilCloseSocket(ListenSock);
  827.            if(++DataPort>LAST_DATA_PORT) DataPort = FIRST_DATA_PORT;
  828.            /* any more control socket response ? */
  829.            GetControlIncoming();
  830.            POST_MSG(FTP_CMD_SUCCESS);
  831.           } /* end-switch(wParam) */
  832.       break;
  833.  
  834.     case WM_CHAR:
  835.       /* user has typed character */
  836.       if(wParam==CR)
  837.         {/* do the CR */
  838.          DisplayChar((char)wParam);
  839.          /* user has completed input */
  840.          ConnectedMenuState();
  841.          DestroyCaret();
  842.          DisplayChar(LF);
  843.          InBuffer[InBufLen] = '\0';
  844.          /* execute command */
  845.          switch(InBufCmd)
  846.             {case MSG_FTP_CWD:
  847.                /* change working directory */
  848.                InBufCmd = 0;
  849.                wsprintf((LPSTR)Temp,"CWD %s",(LPSTR)InBuffer);
  850.                if(!StillConnected()) break;
  851.                AsyncCommand((LPSTR)Temp, FTP_CMD_SUCCESS, FTP_CMD_FAILURE,
  852.                             ASYNC_MULTIPLE_CODED);
  853.                break;
  854.  
  855.              case MSG_FTP_CONNECT:
  856.                /* connect to remote host */
  857.                InBufCmd = 0;
  858.                DoingCmdMenuState();
  859.                /* check FTP host name */
  860.                if( lstrlen((LPSTR)InBuffer) == 0)
  861.                  {DisplayLine("Missing FTP address");
  862.                   NotConnectedMenuState();
  863.                   break;
  864.                  }
  865.                DisplayString("Connecting to ");
  866.                DisplayLine((LPSTR)InBuffer);
  867.                SetCursor(WaitCursor);
  868.                /* connect to server */
  869.                ControlSock = AsyncConnect(hMainWnd,"FTP",(LPSTR)InBuffer,
  870.                           FTP_PORT,  FTP_CONN_SUCCESS,
  871.                           FTP_CONN_FAILURE, ASYNC_MULTIPLE_CODED);
  872.                if((int)ControlSock<0)
  873.                   DisplayLine("Control socket error");
  874.                /* get local address if don't already have it */
  875.                if( MyHostAddr == 0)
  876.                    MyHostAddr = GetAddrFromSock(ControlSock, (LPSTR)MyDottedAddr);
  877.                break;
  878.  
  879.              case MSG_FTP_GET:
  880.                /* get (receive) file */
  881.                DoingCmdMenuState();
  882.                InBufCmd = 0;
  883.                /* got filename ? */
  884.                if(*InBuffer=='\0')
  885.                  {DisplayLine("Missing filename...");
  886.                   break;
  887.                  }
  888.                lstrcpy((LPSTR)Filename, (LPSTR)InBuffer);
  889.                /* open file for write */
  890.                FileHandle = _lcreat(Filename,0);
  891.                if(FileHandle<0)
  892.                  {wsprintf((LPSTR)Temp,"Cannot create '%s'", Filename);
  893.                   DisplayLine((LPSTR)Temp);
  894.                   break;
  895.                  }
  896.                if(StillConnected()) POST_MSG(FTP_GET_BEGIN);
  897.                break;
  898.  
  899.              case MSG_FTP_PUT:
  900.                /* put (send) file */
  901.                DoingCmdMenuState();
  902.                InBufCmd = 0;
  903.                /* got filename ? */
  904.                if(*InBuffer=='\0')
  905.                  {DisplayLine("Missing filename...");
  906.                   break;
  907.                  }
  908.                lstrcpy((LPSTR)Filename, (LPSTR)InBuffer);
  909.                /* open file for read */
  910.                FileHandle = _lopen(Filename,OF_READ|OF_SHARE_DENY_WRITE);
  911.                if(FileHandle<0)
  912.                  {wsprintf((LPSTR)Temp,"Cannot open '%s'", Filename);
  913.                   DisplayLine((LPSTR)Temp);
  914.                   break;
  915.                  }
  916.                if(StillConnected()) POST_MSG(FTP_PUT_BEGIN);
  917.                break;
  918.  
  919.              default:
  920.                break;
  921.             } /* end-switch(InBufCmd) */
  922.          ConnectedMenuState();
  923.          *InBuffer = '\0';
  924.         } /* end-if(wParam==CR) */
  925.       else Add2Buffer((char)wParam);
  926.       break;
  927.  
  928.     default:
  929.       return (DefWindowProc(hMainWnd, iMsg, wParam, lParam));
  930.    }
  931.  return 0;
  932.  
  933. } /* end MainWndProc */